MySQL Binlog(十)——MySQL字段存储格式——字符型字段类型
前言
本文继续介绍binlog中字符类型字段的存储格式。
字符型字段类型
中文等字符存储以该字段的字符集规定存储二进制数据。
CHAR和VARCHAR类型
- [NATIONAL] CHAR[( M )] [CHARACTER SET charset_name ] [COLLATE collation_name ]
定长字符串存储时总是使用空格填充右侧达到指定长度。M表示字符串列的长度。M的范围是0到255。省略的花,长度为1。
CHAR是CHARACTER的简写。NATIONAL CHAR(或简写NCHAR)是标准的定义CHAR列应该使用默认字符集的SQL方法。MySQL4.1及更高版本使用utf8作为默认字符集。
CHAR BYTE是BINARY的别名。这是为了保证兼容性。
MySQL允许定义创建一个CHAR(0)的列。这主要用于必须有一个列,而实际上并不使用值,用以与旧版本的应用程序相兼容。当需要只有两个值的列时CHAR(0)也很不错:定义了CHAR(0)NULL的列只占用一位,可只取值NULL和’’(空字符串)
- [NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name]
变长字符串。M表示最大列长度。M的范围是0到65535。VARCAHR的最大长度由最长行的大小(所有列的共享65535字节)和字符集决定。例如,utf8字符需要多达每个字符三个字节,所以VARCHAR列最多指定21844个字符。
MySQL存储VARCHAR时使用一个或两个字节的前缀+数据。长度前缀表示内容占用的字节数。当列长度不超过255个字节长度前缀占一个字节,当列长度超过255个字节长度前缀占两个字节。
VARCHAR是CHARACTER VARYING的简写。
BINARY和VARBINARY类型
- BINARY(M)
BINARY类型与CHAR类型相似,不过存储的是二进制字节字符串而不是非二进制字符串。M表示列的长度(以字节为单位)
- VARBINARY(M)
VARBINARY类型与VARCHAR类型相似,不过存储的是二进制字节字符串而不是非二进制字符串。M表示最大列长度(以字节为单位)
BLOB和TEXT类型
- TINYBLOB
这种BLOB列的最大长度是65535(2^8-1)个字节。存储每个TINYBLOB列时使用一个字节的前缀长度记录内容占用的字节数。
- BLOB[(M)]
BLOB列的最大长度是65535(2^16-1)个字节。存储每个BLOB列时使用两个字节的前缀长度记录内容占用的字节数。
- MEDIUMBLOB
这种BLOB列的最大长度是16777215(2^24-1)个字节。存储每个MEDIUMBLOB列时使用三个字节的前缀长度记录内容占用的字节数。
- LONGBLOB
这种BLOB列的最大长度是4294967295或者(2^32-1)个字节。LONGBLOB列的最大有效长度取决于客户端/服务器协议配置的最大包大小和可用内存。存储每个LONGBLOB列时使用四个字节的前缀长度记录内容占用的字节数。
- TINYTEXT [CHARACTER SET charset_name ] [COLLATE collation_name ]
这种TEXT列的最大长度是255(2^8-1)个字节。如果内容包含多字节字符,那么最大有效长度将减少。存储每个TINYTEXT时使用一个字节的前缀长度记录内容占用的字节数。
- TEXT[( M )] [CHARACTER SET charset_name ] [COLLATE collation_name ]
TEXT列的最大长度是65535(2^16-1)个字节。如果内容包含多字节字符,那么最大有效长度将减少。存储每个TEXT列时使用两个字节的前缀长度记录内容占用的字节。
可以给出该类型的可选长度M。如果指定了,那么MySQL会创建一个最小的,但可以容纳M字节长度的TEXT列。
- MEDIUMTEXT [CHARACTER SET charset_name ] [COLLATE collation_name ]
这种TEXT列的最大长度是16,777,215(224-1)个字节。如果内容包含多字节字符,那么最大有效长度将减少。存储每个MEDIUMTEXT列时使用三个字节的前缀长度记录内容占用的字节数。
- LONGTEXT [CHARACTER SET charset_name ] [COLLATE collation_name ]
这种TEXT列的最大长度是4,294,967,295或者4GB(232-1)个字节。如果内容包含多字节字符,那么最大有效长度将减少。LONGTEXT列的最大有效长度取决于客户端/服务器协议中配置的最大包大小和可用内存。存储每个LONGTEXT列时使用四个字节的前缀长度记录内容占用的字节数。
ENUM类型
- ENUM( ‘ value1 ‘,’ value2 ‘,…) [CHARACTER SET charset_name ] [COLLATE collation_name ]
枚举类型。属于字符串对象,允许从’ value1 ‘,’ value2 ‘,…,NULL或特殊的’’错误值 列表中选取一个值。ENUM值内部用整数表示。
ENUM列最多可以有65,535个不同的元素(实际的限制小于3000个元素)。一张表可以不超过255个唯一的元素,列表定义中ENUM和SET列视为一组。
SET类型
- SET(‘ value1 ‘,’ value2 ‘,…) [CHARACTER SET charset_name ] [COLLATE collation_name ]
设置类型。属于字符串对象,可以有零个或多个值,必须从’ value1 ‘,’ value2 ‘,…中选取值,SET值内部用整数表示。
SET列最多可以有64个不同的元素。一张表可以不超过255个唯一的元素,列表定义中ENUM和SET列视为一组。
字符型数据存储格式
解析环境描述
表结构定义
1 | CREATE TABLE `string_table` ( |
表数据展示
1 | root@localhost : gangshen 07:37:31> insert into string_table values('abcdefg','abc','abcdefghijklmnopqrstuvwxyz','c','two'); |
然后从binlog文件中拿到,对应的Table_map_event和Writes_rows_event对应的字节内容,开始解析
元数据解析
Table_map_event字节解析
1 | 公共头部部分省略。。。 |
从Table_map_event中可以按照上面的讲述,解析出表中所有的字段类型以及对应的元数据,按照顺序分别是:
第一个字段:0x0f=MYSQL_TYPE_VARCHAR 元数据0xdc05表示字段最多占用的字节数,因为是小端存储,所以该字段最多占用0x05dc=1500字节。这个占用的字节数取决于表的字符集,因为表的字符集为utf8,所以每个字符最多占用3个字节,所以该字段最多占用500*3个字节。
第二个字段:0xfe=MYSQL_TYPE_STRING,因为是MYSQL_TYPE_STRING类型,所以其真实的字段类型应该是元数据第一个字节(0xfe)和0x30做与运算之后的结果, 第二个字节表示该字段最多占用的字节数,所以该字段最多占用0xb4=180个字节
第三个字段:0x12=MYSQL_TYPE_BLOB 元数据0x02表示该字段类型为BLOB/TEXT类型
第四个字段:0x11=MYSQL_TYPE_STRING,所以其真实的字段类型应该是元数据的第一个字节(0xf8)和0x30做与运算之后的结果,即其真实类型是MYSQLTYPE_SET第二个字节表示该字段最多占用的字节数,所以该字段最多占用0x01个字节的内容。
第五个字段:0x11=MYSQL_TYPE_STRING,所以其真实的字段类型应该是元数据的第一个字节(0xf8)和0x30做与运算之后的结果,即其真实类型是MYSQLTYPE_SET第二个字节表示该字段最多占用的字节数,所以该字段最多占用0x01个字节的内容。
字符型数据“值”解析
Write_rows_log_event字节解析
1 | 公共头部部分省略。。。 |
MYSQL_TYPE_VARCHAR字段解析
MYSQL_TYPE_VARCHAR类型字段由长度和字符串内容两部分组成,长度由由字段的元数据决定,字段的元数据表示该字段最大占用字节数。如果元数据小于255,则MYSQL_TYPE_VARCHAR类型使用一个字节表示字符串长度,长度后面紧接着就是字符串的内容;如果元数据大于等于255,则MYSQL_TYPE_VARCHAR类型使用两个字节表示字符串长度(小端存储),长度后面紧接这就是字符串的内容。
在上面的例子中,col1的字段类型为MYSQL_TYPE_VARCHAR类型,且元数据为0x05dc=2500大于255,所以使用两个字节表示字符串长度,所以字符串长度为0x0700,因为是小端存储,所以实际为0x0007,即字符串长度为7个字节。紧接着读取7个字节的内容0x61626364656667转换为ascii为abcdefg,所以col1的字段值为abcdefg
MYSQL_TYPE_STRING字段解析
MYSQL_TYPE_STRING类型字段由长度和字符串内容两部分组成,长度由由字段的元数据决定,字段的元数据表示该字段最大占用字节数。如果元数据小于255,则MYSQL_TYPE_STRING类型使用一个字节表示字符串长度,长度后面紧接着就是字符串的内容;如果元数据大于等于255,则MYSQL_TYPE_STRING类型使用两个字节表示字符串长度(小端存储),长度后面紧接这就是字符串的内容。
在上面的例子中,col2的字段类型是MYSQL_TYPE_STRING类型,且元数据中最大占用字节数为0xb4=180小于255,所以使用一个字节表示字符串长度,所以字符串长度为0x03=3个字节。紧接着读取3个字节的内容0x616263专户为ascii为abc,所以col2的字段值为abc
MYSQL_TYPE_BLOB字段解析
MYSQL_TYPE_BLOB类型字段由长度和字符串内容两部分组成,长度由字段的元数据决定,字段的元数据表示BLOB的类型。如果元数据是1,表示是TINYBLOB/TINYTEXT类型,则MYSQL_TYPE_BLOB类型使用一个字节表示字符串长度,长度后面紧接着就是字符串的内容;如果元数据是2,表示是BLOB/TEXT类型,则MYSQL_TYPE_BLOB类型使用两个字节表示字符串长度(小端存储),长度后面紧接着就是字符串内容;如果元数据是3,表示是MEDIUMBLOB/MEDIUMTEXT类型,则MYSQL_TYPE_BLOB类型使用三个字节表示字符串长度(小端存储),长度后面紧接着就是字符串内容;如果元数据是4,表示是LONGBLOB/LONGTEXT类型,则MYSQL_TYPE_BLOB类型使用四个字节表示字符串长度(小端存储),长度后面紧接着就是字符串内容。
在上面的例子中,col3字段的类型是MYSQL_TYPE_BLOB类型,且元数据为0x02,表示类型为BLOB/TEXT类型,说明该字段使用两个字节表示字符串的长度。所以字符串长度为0x1a00,因为是小端存储,所以字符串长度为0x001a=26,紧接着读取26个字节的内容0x6162636465666768696a6b6c6d6e6f707172737475767778797a转换为ascii为abcdefghijklmnopqrstuvwxyz,所以col3的字段值为abcdefghijklmnopqrstuvwxyz。
MYSQL_TYPE_SET字段解析
MYSQL_TYPE_SET类型字段内容取决于字段定义SET的数量,表示字段值所需字节数量可以从字段元数据的第二个字节获取到,第二个字节表示内容长度。MYSQL_TYPE_SET类型字段内容采用压缩的表示方法,对应比特位置1则表示值是该位,但是从binlog中无法解析出SET类型内容的具体类型,只能解析出对应的比特位表示方式。
在上面的例子中,col4字段的类型是MYSQL_TYPE_SET,且元数据中表示该字段使用0x01个字节表示字段值,所以col4在Write_rows_log_event占用1个字节的内容,为0x04,转换为二进制为b’100’,从右往左第3位比特位上是1,表示值为set定义中第三个。从Write_rows_log_event中,无法解析出set定义的每个项,查看建表语句,得知set定义中第三个为c,即col4字段的值为c
MYSQL_TYPE_ENUM字段解析
MYSQL_TYPE_ENUM类型字段内容取决于字段定义ENUM数量,表示字段值所需字节数量可以从字段元数据的第二个字节获取到,第二个字节表示内容长度。
当元数据第二个字节等于1的时候,MYSQL_TYPE_ENUM字段值使用一个字节表示,当元数据第二个字节等于2的时候,MYSQL_TYPE_ENUM字段值使用两个字节表示。
在上面的例子中,col5字段的类型是MYSQL_TYPE_ENUM,且元数据中表示该字段使用0x01个字节表示字段值,所以col5在Write_rows_log_event中占用1个字节的内容,为0x02,转换为10进制为2,即表示值为enum定义中的第2个。在Write_rows_log_event中,无法解析出enum定义的每个项,查看建表语句,得知enum定义中第二个值为two,即col5字段的值为two。